
// 格式化子项类定义与实现

#ifndef __FORMAT__
#define __FORMAT__

#include "message.hpp"
#include <vector>
#include <cassert>
#include <sstream>
#include <map>

using std::make_shared;
using std::shared_ptr;
using std::string;
using std::vector;
using std::map;
using std::cout;
using std::endl;
using std::pair;
using std::make_pair;

namespace violet_log
{
    // 抽象格式化项
    // 基类
    class format_item
    {
    public:
        using ptr = shared_ptr<format_item>;
        virtual void format(std::ostream &out, const log_message &msg) = 0;
    };

    // 时间，等级，文件名，行号，日志器名，信息，线程id，制表符，换行，其他
    // 时间子类
    class time_format_item : public format_item
    {
    public:
        time_format_item(const std::string &format = "%H:%M:%S")
            : _format(format)
        {
            if (format.empty())
                _format = "%H:%M:%S";
        }

        void format(std::ostream &out, const log_message &msg)
        {
            time_t time_stamp = msg._time;

            // man localtime
            // struct tm *localtime_r(const time_t *timep, struct tm *result);
            struct tm t;
            localtime_r(&time_stamp, &t);

            // man strftime
            // size_t strftime(char *s, size_t max, const char *format, const struct tm *tm);
            char s[64] = {0};
            strftime(s, 63, _format.c_str(), &t);

            out << s;
        };

    private:
        std::string _format; // 格式化字符串
    };

    // 等级子类
    class level_format_item : public format_item
    {
    public:
        void format(std::ostream &out, const log_message &msg)
        {
            out << log_level::to_string(msg._level);
        }
    };

    // 文件名子类
    class file_format_item : public format_item
    {
    public:
        void format(std::ostream &out, const log_message &msg)
        {
            out << msg._file;
        }
    };

    // 行号子类
    class line_format_item : public format_item
    {
    public:
        void format(std::ostream &out, const log_message &msg)
        {
            out << msg._line;
        }
    };

    // 日志器名子类
    class logger_format_item : public format_item
    {
    public:
        void format(std::ostream &out, const log_message &msg)
        {
            out << msg._name;
        }
    };

    // 信息子类
    class payload_format_item : public format_item
    {
    public:
        void format(std::ostream &out, const log_message &msg)
        {
            out << msg._payload;
        }
    };

    // 线程id子类
    class tid_format_item : public format_item
    {
    public:
        void format(std::ostream &out, const log_message &msg)
        {
            out << msg._tid;
        }
    };

    // 制表符子类
    class tab_format_item : public format_item
    {
    public:
        void format(std::ostream &out, const log_message &msg)
        {
            out << "    ";
        }
    };

    // 换行子类
    class newline_format_item : public format_item
    {
    public:
        void format(std::ostream &out, const log_message &msg)
        {
            out << "\n";
        }
    };

    // 其他子类
    class other_format_item : public format_item
    {
    public:
        other_format_item(const std::string &s = "")
            : _s(s)
        {
        }

        void format(std::ostream &out, const log_message &msg)
        {
            out << _s;
        }

    private:
        std::string _s;
    };

    // 格式化器
    class formatter
    {
    public:
        using ptr = std::shared_ptr<formatter>;

        formatter(const std::string &pattern = {"[%d{%H:%M:%S}][%n][%t][%l][%f:%L]%T%m%N"})
            : _pattern(pattern)
        {
            assert(parse_pattern());
        }

        // 对msg格式化
        std::ostream& format(std::ostream &out, log_message &msg)
        {
            for (auto &item : _item)
            {
                item->format(out, msg);
            }
            return out;
        }
        std::string format(log_message &msg)
        {
            // string流
            std::stringstream ss;
            format(ss, msg);
            return ss.str();
        }

    private:
        // 解析格式化字符串
        bool parse_pattern()
        {
            vector<pair<string, string>> kv;
            size_t pos = 0;
            while(pos < _pattern.size())
            {
                if(_pattern[pos] != '%')
                {
                    string v;
                    v += _pattern[pos];
                    kv.push_back(make_pair("", v));

                    ++pos;
                    continue;
                }

                if(_pattern[pos] == '%')
                {
                    if(pos + 1 == _pattern.size())
                    {
                        cout << "最后一个字符为%" << endl;
                        return false;
                    }

                    if(_pattern[pos + 1] == 'd')
                    {
                        if(pos + 1 == _pattern.size()
                        || (pos + 2 < _pattern.size() && _pattern[pos + 2] != '{'))
                        // 字符串以%d为结尾
                        // 或pos+2小于size的前提下pos+2不为'{'
                        {
                            kv.push_back(make_pair("d", ""));

                            pos += 2;
                            continue;
                        }

                        size_t left = _pattern.find_first_of('{', pos);
                        size_t right = _pattern.find_first_of('}', pos);
                        if(right == string::npos)
                        {
                            cout << "无}字符" << endl;
                            return false;
                        }
                        string v(_pattern.substr(left + 1, right - left - 1));
                        kv.push_back(make_pair("d", v));

                        pos = right + 1;
                        continue;
                    }
                    else if(_pattern[pos + 1] == 'n') kv.push_back(make_pair("n", ""));
                    else if(_pattern[pos + 1] == 't') kv.push_back(make_pair("t", ""));
                    else if(_pattern[pos + 1] == 'l') kv.push_back(make_pair("l", ""));
                    else if(_pattern[pos + 1] == 'f') kv.push_back(make_pair("f", ""));
                    else if(_pattern[pos + 1] == 'L') kv.push_back(make_pair("L", ""));
                    else if(_pattern[pos + 1] == 'T') kv.push_back(make_pair("T", ""));
                    else if(_pattern[pos + 1] == 'm') kv.push_back(make_pair("m", ""));
                    else if(_pattern[pos + 1] == 'N') kv.push_back(make_pair("N", ""));
                    else if(_pattern[pos + 1] == '%') kv.push_back(make_pair("", "%"));
                    else {cout << "未知格式化字符:%" << _pattern[pos + 1] << endl; return false;}

                    pos += 2;
                    //continue;
                }
            }

            for(auto& x : kv)
            {
                _item.push_back(creat_item(x.first, x.second));
            }
            
            return true;
        }

        // 根据字符串创建不同的格式化子项
        std::shared_ptr<format_item> creat_item(const std::string &key, const std::string &val)
        //format_item::ptr creat_item(const std::string &key, const std::string &val)
        {
            // %d 日志时间
            // %t 线程id
            // %l 日志等级
            // %f 源码文件名
            // %L 源码行号
            // %m 日志消息
            // %n 日志器名
            // %T 制符表
            // %N 换行

            if (key == "d") return make_shared<time_format_item>(val);
            else if(key == "t") return make_shared<tid_format_item>();
            else if(key == "l") return make_shared<level_format_item>();
            else if(key == "f") return make_shared<file_format_item>();
            else if(key == "L") return make_shared<line_format_item>();
            else if(key == "m") return make_shared<payload_format_item>();
            else if(key == "n") return make_shared<logger_format_item>();
            else if(key == "T") return make_shared<tab_format_item>();
            else if(key == "N") return make_shared<newline_format_item>();
            else return make_shared<other_format_item>(val);//勿忘传val
        }

    private:
        std::string _pattern;                // 格式化字符串
        std::vector<format_item::ptr> _item; // 格式化子项数组
    };
}

#endif